from odoo import fields, models, _
from odoo.exceptions import UserError


class MaterialPreparationSaleLineReport(models.Model):
    _name = 's.material.preparation.sale.line.report'
    _description = 'Material preparation'
    _auto = False
    _order = 'id'

    sale_id = fields.Many2one('sale.order', 'Sale')
    sale_order_line_id = fields.Many2one('sale.order.line', 'Sale Line')
    forecast_order_id = fields.Many2one('s.forecast.order', string='Forecast Order')
    forecast_order_line_id = fields.Many2one('s.forecast.order.line', string='Forecast Order')
    product_id = fields.Many2one('product.product', 'Product')
    product_qty = fields.Float('qty')
    planned_qty = fields.Float('planned qty')
    pm_quantity = fields.Float('Prepared quantity')  # 已备料数量
    date_order = fields.Datetime('Order Date')
    commitment_date = fields.Datetime('Commitment Date')
    prepared_materials = fields.Boolean('Prepared materials')
    presets_bom_id = fields.Many2one('sb.presets.bom', 'presets bom')
    bom_id = fields.Many2one('mrp.bom')

    order_type = fields.Selection([('sale', 'sale'), ('forecast', 'forecast')], string='order type')

    notes = fields.Text('Notes', compute='_compute_notes')

    inventory_qty = fields.Float(string='Inventory Quantity', readonly=True, compute='_compute_inventory_qty')

    status = fields.Selection([
        ('draft', 'Draft'),
        ('active', 'Active'),
        ('invoiced', 'Invoiced'),
        ('hold', 'Hold'),
        ('closed', 'Closed'),
        ('completed', 'Completed'),
        ('part_completed', 'Part Completed'),
        ('marketing_confirmed', 'Marketing'),  # Marketing Confirmed
        ('engineering_confirmed', 'Engineering'),  # Engineering Confirmed
        ('material_calculated', 'Materials Calculated'),  # Materials Calculated
        ('requisition_generated', 'Requisition Generated'),  # Requisition Generated
        ('done', 'Done'),  # Done
        ('cancel', 'Cancel'),  # Cancelled
        ('cancelled', 'Cancelled')
    ], string='Status', help='外部更改模块的，关键字段')

    def _compute_inventory_qty(self):
        for rec in self:
            rec.inventory_qty = rec.product_id.compute_version_qty_available()

    def _compute_notes(self):
        for rec in self:
            notes = ''
            if rec.sale_order_line_id:
                notes = rec.sale_order_line_id.s_pm_notes or ''
                product_lock_ids = self.env['s.product.lock'].search([
                    ('sale_order_line_id', '=', rec.sale_order_line_id.id),
                    ('active', 'in', (True, False)),
                    ('cancel', '=', True)
                ])
                for line in product_lock_ids:
                    notes += f'物料 {line.product_id.name} , \n解锁释放数量: {line.qty} \n'
            if rec.forecast_order_line_id:
                product_lock_ids = self.env['s.product.lock'].search([
                    ('forecast_order_line_id', '=', rec.forecast_order_line_id.id),
                    ('active', 'in', (True, False)),
                    ('cancel', '=', True)
                ])
                for line in product_lock_ids:
                    notes += f'物料 {line.product_id.name} , \n解锁释放数量: {line.qty} \n'
            rec.notes = notes

    def action_select_sale_material_preparation(self):
        order_line = self.filtered(lambda x: x.product_id.detailed_type == 'product')
        # if self.filtered(lambda x: x.prepared_materials):
        #     raise UserError(_('Secondary material preparation is not allowed'))
        if not order_line:
            raise UserError(_('There are no products available for preparation'))
        wizard = self.env['s.sale.order.material.preparation.wizard']

        preparation_type = self._context.get('preparation_type', '')
        res = wizard.with_context({
            'default_sale_order_line_id': self.sale_order_line_id.id,
            'default_forecast_order_line_id': self.forecast_order_line_id.id,
            'default_sale_id': self.sale_id.id,
            'default_forecast_order_id': self.forecast_order_id.id,
            'preparation_type': preparation_type,
        }).default_get(list(wizard.fields_get()))

        res_id = self.env['s.sale.order.material.preparation.wizard'].create(res)
        res_id.onchange_qty()
        return {
            'name': _('material preparation'),
            'type': 'ir.actions.act_window',
            'view_mode': 'form',
            'res_model': 's.sale.order.material.preparation.wizard',
            'res_id': res_id.id
            # 'context': {
            #     'default_sale_order_line_ids_str': ','.join([str(i.id) for i in self.mapped('sale_order_line_id')])
            # },
            # 'target': 'new',
        }

    def action_view_material_preparation(self):
        self.ensure_one()
        action = self.env["ir.actions.act_window"]._for_xml_id('sb_base.action_s_product_lock')
        domain = [
            ('active', 'in', (True, False)),
            ('cancel', '=', False),
        ]
        if self.forecast_order_line_id:
            domain.append(('forecast_order_line_id', '=', self.forecast_order_line_id.id))
        elif self.sale_order_line_id:
            domain.append(('sale_order_line_id', '=', self.sale_order_line_id.id))
        action['domain'] = domain
        return action

    def action_cancel_sale_material_preparation(self):
        self.ensure_one()
        replace_product_ids = self.env['s.mrp.bom.product.replace']
        lock_ids = self.env['s.product.lock']
        if self.forecast_order_id:
            replace_product_ids |= self.env['s.mrp.bom.product.replace'].search([
                ('forecast_order_line_id', '=', self.forecast_order_line_id.id)
            ])
            lock_ids |= self.env['s.product.lock'].search([
                ('forecast_order_line_id', '=', self.forecast_order_line_id.id),
                ('active', 'in', (True, False))
            ])
        if self.sale_id:
            replace_product_ids |= self.env['s.mrp.bom.product.replace'].search([('sale_id', '=', self.sale_id.id)])
            lock_ids |= self.env['s.product.lock'].search([
                ('sale_order_line_id', '=', self.sale_order_line_id.id),
                ('active', 'in', (True, False))
            ])
        # unlink_lock_ids = lock_ids.filtered(lambda x: x.lock_type == 'stock')
        replace_product_ids.unlink()
        for rec in lock_ids.filtered(lambda x: x.lock_type == 'prepare' and not x.cancel):
            if rec.purchase_requisition_id.state in ('section_purchasing', 'purchasing', 'done'):
                raise UserError(_('%s , %s, This status does not allow cancellation, please handle it manually', rec.purchase_requisition_id.name, rec.purchase_requisition_id.state))
            rec.purchase_requisition_id.button_cancel()
        self.forecast_order_line_id.write({'pm_quantity': 0})
        self.sale_order_line_id.write({'s_pm_quantity': 0})
        lock_ids.write({'x_delete': True})
        lock_ids.sudo().action_archive()

    @property
    def _table_query(self):
        sql = """
         select so.id sale_id, 
                sol.id id, 
                coalesce(so.status, 'draft') status,
                sol.id sale_order_line_id, 
                null forecast_order_id,
                null forecast_order_line_id,
                sol.product_uom_qty product_qty,
                sol.s_planned_qty planned_qty,
                sol.s_pm_quantity pm_quantity,
                sol.product_id product_id,
                sol.s_prepared_materials prepared_materials,
                so.date_order date_order,
                so.commitment_date commitment_date,
                'sale' order_type,
                (select id from sb_presets_bom where product_id = pp.id and sb_workflow_state = 'approve' limit 1) presets_bom_id,
                (select mrp_bom.id from mrp_bom left join product_template  on mrp_bom.product_tmpl_id = product_template.id 
                  where mrp_bom.product_tmpl_id = pt.id and mrp_bom.active = TRUE and product_template.s_disable_down_card IS NOT TRUE limit 1) bom_id
            from sale_order_line sol
                     left join sale_order so on sol.order_id = so.id
                     left join product_product pp on sol.product_id = pp.id
                     left join product_template pt on pp.product_tmpl_id = pt.id
            where pt.detailed_type = 'product'
              and sol.s_planned_qty < sol.product_uom_qty
              and sol.qty_delivered = 0 
              and sol.s_plan_close != true
              and so.status not in ('closed', 'cancelled')
              and so.state != 'cancel'
         union all 
         select null                                                                             sale_id,
                1000000 + row_number() OVER ()                                                         id,
                coalesce(sfo.state, 'draft')                                                     status,
               null                                                                             sale_order_line_id,
               sfo.id                                                                           forecast_order_id,
               sfol.id                                                                          forecast_order_line_id,
               sfol.market_forecast_quantity                                                    product_qty,
               0                                                                                planned_qty,
               sfol.pm_quantity                                                                 pm_quantity,
               sfol.product_id                                                                  product_id,
               false                                                                            prepared_materials,
               sfo.forecast_date                                                                date_order,
               null                                                                             commitment_date,
               'forecast'                                                                       order_type,
               
               (select id
                from sb_presets_bom
                where product_id = pp.id
                  and sb_workflow_state = 'approve'
                limit 1)                                                                        presets_bom_id,
               (select id from mrp_bom where product_tmpl_id = pt.id and active = TRUE limit 1) bom_id
        from s_forecast_order_line sfol
                 left join s_forecast_order sfo on sfol.forecast_order_id = sfo.id
                 left join product_product pp on sfol.product_id = pp.id
                 left join product_template pt on pp.product_tmpl_id = pt.id
        where pt.detailed_type = 'product'
          and sfo.state in ('engineering_confirmed', 'material_calculated', 'requisition_generated', 'done')
        """
        return sql
